package com.bflow.impl;

import com.bflow.api.IBflowCacheService;
import com.bflow.api.IBflowDefineActRouteService;
import com.bflow.api.IBflowDefineActService;
import com.bflow.api.IBflowDefineProcessService;
import com.bflow.api.bo.BflowDefineActBo;
import com.bflow.api.bo.BflowDefineActRouteBo;
import com.bflow.api.bo.BflowDefineProcessBo;
import com.bflow.api.bo.BflowDefineProcessQueryParam;
import com.bflow.api.constant.BflowConstant;
import com.bflow.api.constant.BflowConstant.ProcessType;
import com.bflow.commons.bean.PageResult;
import com.bflow.commons.consts.CommConst;
import com.bflow.commons.exception.BizException;
import com.bflow.commons.service.BaseService;
import com.bflow.commons.util.StrUtil;
import com.bflow.dao.BflowDefineProcessDao;
import com.bflow.dao.po.BflowDefineProcessPo;
import com.bflow.util.*;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 功能：BflowDefineProcess 流程定义-实现业务接口
 * 作者：haowen
 * 日期：2018-12-13
 */
@Service("bflowDefineProcessService")
public class BflowDefineProcessServiceImpl extends BaseService<BflowDefineProcessPo, BflowDefineProcessBo> implements IBflowDefineProcessService<BflowDefineProcessPo, BflowDefineProcessBo> {

	@Autowired
	private BflowDefineProcessDao dao;
	@Autowired
	private IBflowDefineActRouteService bflowDefineActRouteService;
	@Autowired
	private IBflowDefineActService<?, BflowDefineActBo> bflowDefineActService;
	@Autowired
	private IBflowCacheService bflowCacheService;

	@Override
	protected BflowDefineProcessDao getDao() {
		return dao;
	}

	/**
	 * 插入流程定义数据
	 * @param bo
	 * @return
	 */
	@Override
	public String add(BflowDefineProcessBo bo) {
		if(StringUtils.isBlank(bo.getId())) {
			bo.setId(SysSeqUtil.genId());
			bo.setStatus(CommConst.STATUS_N);
		}
		bo.setCreateTime(new Date());
		bo.setUpdateTime(new Date());
		BflowDefineProcessPo po = BeanMapper.map(bo, BflowDefineProcessPo.class);
		if (dao.insert(po) <= 0) {
			throw new BizException("新增失败");
		}
		return bo.getId();
	}


	@Transactional
	@Override
	public void save(BflowDefineProcessBo bo) {
		String[] actSet = bo.getActSet().split(BflowConstant.ACT_SPLIT);
		AssertUtil.isNotEmpty(actSet, "活动集合不能为空");
		String startActId = actSet[0];
		List<BflowDefineActRouteBo> routeBos = bo.getRouteBos();
		bo.setStartActId(startActId);
		String procId = bo.getId();

		boolean isSet = ProcessType.SET.eq(bo.getType());
		//验证 条件分支
		validRoutes(routeBos, startActId, isSet);
		if(StrUtil.isBlank(procId)){
			//新增
			procId = add(bo);
			//高级 自定义
			if(isSet){
				bflowDefineActRouteService.batchInsert(routeBos, procId, 1);
			}else{
				bflowDefineActRouteService.setDefaultActRoute(actSet, procId, 1);
			}
		}else{
			//对比 活动集合是否变化
			if(isChangeActSet(bo.getActSet(), procId)){
				//新流程
				bo.setVersion(getLastProcessVersion(bo.getKey()) + 1);
				procId = add(bo);
				//保存 路由条件
				bflowDefineActRouteService.batchInsert(routeBos, procId, bo.getVersion());
				//移除缓存
				removeCache(bo.getKey(), procId);
			}else{
				bo.setVersion(getLastProcessVersion(bo.getKey()));
				bo.setUpdateTime(new Date());
				update(bo);
				//保存 路由条件
				bflowDefineActRouteService.batchDel(procId, bo.getVersion());
				bflowDefineActRouteService.batchInsert(routeBos, procId, bo.getVersion());
			}
		}
	}

	@Override
	public void deploy(String id) throws BizException {
		BflowDefineProcessBo processBo = findById(id);
		AssertUtil.isNotEmpty(processBo, "找不到流程");

		//检查 是否已画图
		// ....


		//更新流程
		processBo.setStatus(CommConst.STATUS_Y);
		processBo.setUpdateTime(new Date());
		this.update(processBo);
	}

	private void validRoutes(List<BflowDefineActRouteBo> routeBos, String startActId, boolean isSet){
		if(isSet) {
			AssertUtil.isNotEmpty(routeBos, "条件分支不能为空");
			// 检查 是否为一条完整流程
			boolean isFull = ActRouteUtil.isFullProcessActLink(startActId, routeBos);
			AssertUtil.isTrue(isFull, "流程有误, 请设置条件分支值.");
		}
	}

	private boolean isChangeActSet(String newActSet, String id){
		BflowDefineProcessBo oldProcessBo = findById(id);
		return !newActSet.equals(oldProcessBo.getActSet());
	}

	@Override
	public BflowDefineProcessBo detail(String id) {
		BflowDefineProcessBo bo = findById(id);
		if(bo != null){
			String[] actSet = bo.getActSet().split(",");
			List<String> list = new ArrayList<>();
			for (String actId : actSet) {
				list.add(bflowDefineActService.getCacheActName(actId));
			}
			bo.setActNameSet(StrUtil.join(list, "###"));
		}
		return bo;
	}

	@Override
	public BflowDefineProcessBo getCache(String id) {
		String cacheKey = "processById:"+id;
		String cache = bflowCacheService.get(cacheKey);
		BflowDefineProcessBo bo = null;
		if(StrUtil.isBlank(cache)){
			bo= findById(id);
			if(bo != null)
				bflowCacheService.put(cacheKey, JsonUtil.toStr(bo));
		}
		return JsonUtil.toJavaObj(cache, BflowDefineProcessBo.class);
	}

	@Override
	public Integer getLastProcessVersion(String procKey) {
		String cacheKey = "processVersionByKey:"+procKey;
		String cache = bflowCacheService.get(cacheKey);
		if(StrUtil.isBlank(cache)){
			Integer value = dao.getLastProcessVersion(procKey);
			if(value != null)
				bflowCacheService.put(cacheKey, value.toString());
			else
				value = 0;
			return value;
		}
		return Integer.parseInt(cache);
	}

	@Override
	public BflowDefineProcessBo getFlowModelBykey(String procKey) {
		AssertUtil.isNotNull(procKey,"模型key不能为空");
		BflowDefineProcessBo query = new BflowDefineProcessBo();
		query.setKey(procKey);
		query.setStatus(CommConst.STATUS_Y);
		BflowDefineProcessBo result = this.getOneBy(query);
		return result;
	}

	private void removeCache(String procKey, String id){
		bflowCacheService.del("processVersionByKey:"+procKey);
		bflowCacheService.del("processById:"+id);
	}

	/**
	 * 查询流程列表及任务关联业务分页数据
	 * @param queryParam
	 * @return
	 * @throws BizException
	 */
	@Override
	public PageResult<BflowDefineProcessBo> findProcessInstancePage(BflowDefineProcessQueryParam queryParam) throws BizException {
		queryParam.setPageDefParam(1, 10); //防止分页为空 设置默认值
		PageResult<BflowDefineProcessBo> pageResult = new PageResult<BflowDefineProcessBo>();
		List<BflowDefineProcessBo> dataList = null;
		long totalCount = getDao().findProcessInstancePageCount(queryParam);
		if(queryParam.getPageBean().getStart() < totalCount){
			List<BflowDefineProcessPo> poList = getDao().findProcessInstancePage(queryParam);
			if (CollectionUtils.isNotEmpty(poList)) {
				dataList = BeanMapper.mapList(poList, getBoClazz());
			}
		}
		pageResult.setTotalCount(totalCount);
		pageResult.setResult(dataList);
		return pageResult;
	}

	/**
	 *查询流程列表及任务关联业务分页记录数
	 * @param queryParam
	 * @return
	 * @throws BizException
	 */
	@Override
	public long findProcessInstancePageCount(BflowDefineProcessQueryParam queryParam) throws BizException {
		return this.getDao().findProcessInstancePageCount(queryParam);
	}

}
